package testApplets;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;

import processing.core.PApplet;
import simpleGeom.*;

public class FinalScaleApplet extends PApplet {
	// Mesh mesh;
	ArrayList<Mesh> meshes;
	Mesh restMesh;
	float realD;
	float y1;
	int nY;
	Mesh mesh;

	public void setup() {
		//scaleToBounds();
		onlyscaleToBounds();
		//scaleAbs();
		exit();
		/*meshes = new ArrayList<Mesh>();
		mesh = new Mesh();
		mesh.loadMesh(this.selectInput());
		mesh.triangulate();
		Box3D bounds = mesh.getBounds();
		y1 = bounds.y1;
		nY = (int) (bounds.getDimY() / 0.2f) + 1;
		realD = bounds.getDimY() / nY;
		restMesh = mesh;

		saveMeshesSimple(selectOutput());*/
	}
	

	Box3D bds=new Box3D(0f,0f,-1.75f,2.0f,3.2f,0f);
	public void scaleSinus(Mesh meshInput){
		float xMin=1.2f;
		float xMax=2.0f;
		float xCompress=0.4f;
		
		float deltaX=xMax-xMin;
		float fac=0.4f/(sin(HALF_PI*0.8f));
		for (int i=0;i<meshInput.getNNodes();i++){
			HasPos3D pt=meshInput.getNode(i);
			if (pt.getX()>xMin){
				float dX=pt.getX()-xMin;
				float xNew = fac*(sin((dX/deltaX)*HALF_PI*0.8f));
				if (xNew<0)println(pt.getX());
				pt.setX(xNew+xMin);
			}
		}
	}
	public void scaleAbs(){
		float sX= 1.2305056f;
		float sY= 1.0345981f;
		float sZ=1.3474264f;
		float tX=-0.072946355f;
		float tY=1.6616038f;
		float tZ=0.014629126f;
		
		String path=this.selectInput();
		File fileIn=new File(path);
		String fileInPath=fileIn.getParent();
		
		String fileInName=fileIn.getName();
		
		Mesh meshInput = new Mesh(path);
		meshInput.scale(sX,sY,sZ);
		meshInput.translate(tX,tY,tZ);
		
		
		// new scale
		
		
		
		/*for (int i=0;i<meshInput.getNNodes();i++){
			HasPos3D pt=meshInput.getNode(i);
			if (pt.getX()>xMin){
			float p=constrain((pt.getX()-xMin)/(xMax/xMin),0,1);
			float xNew = pt.getX() - (sin((-HALF_PI+PI*p))*.5f+0.5f)*xCompress;
			pt.setX(xNew);
			}
		}*/
		
		scaleSinus(meshInput);
		
		float scaleZ=(1.55f/1.75f);
		float scaleY=(3.25f/3.2f);
		float scaleX=1.5f/1.6f;
		
		for (int i=0;i<meshInput.getNNodes();i++){
			HasPos3D pt=meshInput.getNode(i);
			pt.setX(pt.getX()*scaleX);
			pt.setY(pt.getY()*scaleY);
			pt.setZ(pt.getZ()*scaleZ);
		}
		
		
		
		for (int i=0;i<meshInput.getNNodes();i++){
			HasPos3D pt=meshInput.getNode(i);
			float cY=pt.getY();
			
			if (cY<1.1f){
				cY*=0.9218181818f;
			}
			else if (cY<3.2f){
				float dY=3.2f-cY;
				cY=3.2f-dY*1.04f;
			}
			pt.setY(cY);
			
			float cZ=pt.getZ();
			if (cZ>-1.45f){
				cZ=cZ*1.40f/1.45f;
			}
			else if (cZ>-1.55f){
				float dZ=cZ+1.55f;
				cZ=-1.55f+dZ*(0.15f/0.10f);
				
			}
			pt.setZ(cZ);
			
		}
		Box3D newBds=meshInput.getBounds();
		// scale from 0.01f to 0 to -0.01f
		// dX=0.02f
	/*	float startX=-0.03f;
		float midX=0;
		float endX=0.04f;
		
		float maxScale=(endX-startX)/(midX-startX);
		float minScale=1;
		float deltaScale=maxScale-minScale;
		float y2=2.0f;
		float y1=1.5f;
		float deltaY=y2-y1;
		for (int i = 0; i < meshInput.getNNodes(); i++) {
			HasPos3D pt = meshInput.getNode(i);
			float cX = pt.getX();
			float dX = abs(endX - cX);
			if (cX < endX && cX > -startX) {
				float cY = pt.getY();
				if (cY < y2) {
					if (cY > y1) {
						// start 0 end -0.01f;
						float scale = (abs(y2-cY)/deltaY)*deltaScale +minScale;
						pt.setX(endX - scale * dX);
					} else {
						pt.setX(endX - maxScale * dX);
					}
				}
			}
		}*/
		
		String fileOutName=fileInName.substring(0, 1);
		fileOutName+=newBds.toStringCorners()+".obj";
		String pathOut=fileInPath+"/"+fileOutName;
		meshInput.saveMesh(pathOut);
		
		
	}
	public void onlyscaleToBounds(){
		Mesh meshInput = new Mesh(this.selectInput());
		
		Box3D mBds=meshInput.getBounds();
		//float scale=1.14f/(abs(mBds.z1)*2f);
		//scaleX=min(1.2f,scaleX);
		float scale=0.37586548f;
		meshInput.scale(scale,scale,scale);
		mBds=meshInput.getBounds();
		println(mBds);
	
		meshInput.saveMesh(this.selectOutput());
	}
	public void scaleToBounds(Box3D bds){
		Mesh meshInput = new Mesh(this.selectInput());
		Box3D mBds=meshInput.getBounds();
		println(mBds);
		float scaleX=bds.getDimX()/mBds.getDimX();
		float scaleY=bds.getDimY()/mBds.getDimY();
		float scaleZ=bds.getDimZ()/mBds.getDimZ();
		println("xScale: "+scaleX);
		println("yScale: "+scaleY);
		println("zScale: "+scaleZ);
		//scaleX=min(1.2f,scaleX);
		
		meshInput.scale(scaleX,scaleY,scaleZ);
		mBds=meshInput.getBounds();
		
		float tX=bds.x1-mBds.x1;
		float tY=bds.y1-mBds.y1;
		float tZ=bds.z1-mBds.z1;
		println("xTrans: "+tX);
		println("yTrans: "+tY);
		println("zTrans: "+tZ);
		meshInput.translate(tX,tY,tZ);
		meshInput.saveMesh(this.selectOutput());
		
	}
	
	public void splitMeshes() {
		for (int i = 0; i < nY; i++) {
			println("iCut: " + i);
			float cY = y1 + i * realD;
			Mesh[] twoMesh = cutMesh(restMesh, cY);
			// meshes.add(twoMesh[1]);
			restMesh.clear();
			restMesh = twoMesh[0];
			println("nFaces: " + restMesh.getNFaces());
			i++;
		}
	}

	public void saveMeshesSimple(String file) {
		try {
			FileWriter fw = new FileWriter(file);
			BufferedWriter bw = new BufferedWriter(fw);
			int cId = 1;

			for (int j = 0; j < mesh.getNNodes(); j++) {
				MeshNode node = mesh.getNode(j);
				node.id = j;
				bw.write("v " + node.getX() + " " + node.getY() + " "
						+ node.getZ());
				bw.newLine();
			}
			for (int i = 0; i < nY; i++) {
				bw.write("g " + i);
				bw.newLine();
				println("iCut: " + i);
				float cY = y1 + i * realD;
				float cY2 = y1 + (i + 1) * realD;
				for (int j = 0; j < mesh.getNFaces(); j++) {
					MeshFace face = mesh.getFace(j);
					int innerNodes = 0;
					for (int jj = 0; jj < face.getNNodes(); jj++) {
						MeshNode node = face.getNode(jj);
						if (node.y > cY && node.y < cY2) {
							innerNodes++;
						}
					}
					if (innerNodes >= 3) {
						bw.write("f");
						for (int jj = 0; jj < face.getNNodes(); jj++) {
							MeshNode node = face.getNode(jj);
							bw.write(" " + (node.id + cId));
						}
						bw.newLine();
					}
				}
			}
			bw.flush();
			bw.close();
		} catch (Exception e) {
			System.err.println("error writing file");
		}
		println("distance saved");
	}

	public void draw() {

	}

	public void saveMeshes(String file) {
		try {
			FileWriter fw = new FileWriter(file);
			BufferedWriter bw = new BufferedWriter(fw);
			int cId = 1;
			for (int i = 0; i < meshes.size(); i++) {
				Mesh mesh = meshes.get(i);
				bw.write("g " + i);
				bw.newLine();
				for (int j = 0; j < mesh.getNNodes(); j++) {
					MeshNode node = mesh.getNode(j);
					node.id = j;
					bw.write("v " + node.getX() + " " + node.getY() + " "
							+ node.getZ());
					bw.newLine();
				}
				for (int j = 0; j < mesh.getNFaces(); j++) {
					MeshFace face = mesh.getFace(j);
					bw.write("f");
					for (int jj = 0; jj < face.getNNodes(); jj++) {
						MeshNode node = face.getNode(jj);
						bw.write(" " + (node.id + cId));
					}
					bw.newLine();
				}
				cId += mesh.getNNodes();
			}
			bw.flush();
			bw.close();
			// fileOutputStream.close();
		} catch (Exception e) {
			System.err.println("error writing file");
		}
		println("distance saved");
	}

	public Mesh[] cutMesh(Mesh mesh, float y) {
		Mesh[] twoMesh = new Mesh[2];
		Vec3D pt = new Vec3D(0, y, 0);
		Vec3D normal1 = new Vec3D(0, 1, 0);
		Vec3D normal2 = new Vec3D(0, -1, 0);
		Plane plane1 = new Plane(pt, normal1);
		Plane plane2 = new Plane(pt, normal2);
		twoMesh[0] = plane1.cutMesh(mesh);
		twoMesh[1] = plane2.cutMesh(mesh);

		return twoMesh;
	}

}
